<!DOCTYPE html>
<html>
    <head>

        <link rel="canonical" href="http://www.jointjs.com/" />
        <meta name="description" content="Create interactive diagrams in JavaScript easily. JointJS plugins for ERD, Org chart, FSA, UML, PN, DEVS, LDM diagrams are ready to use." />
        <meta name="keywords" content="JointJS, JavaScript, diagrams, diagramming library, UML, charts" />

        <link href="http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700" rel="stylesheet" type="text/css" />
        <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">

        <link rel="stylesheet" href="css/tutorial.css" />
        <link rel="stylesheet" href="../node_modules/prismjs/themes/prism.css">


        <!-- Dependencies: -->
        <script src="../node_modules/jquery/dist/jquery.js"></script>
        <script src="../node_modules/lodash/lodash.js"></script>
        <script src="../node_modules/backbone/backbone.js"></script>


        <link rel="stylesheet" type="text/css" href="../build/joint.min.css" />
        <script type="text/javascript" src="../build/joint.min.js"></script>

        <title>JointJS - JavaScript diagramming library - Getting started.</title>

    </head>
    <body class="language-javascript tutorial-page">

        <script>
            SVGElement.prototype.getTransformToElement = SVGElement.prototype.getTransformToElement || function (toElement) {
                return toElement.getScreenCTM().inverse().multiply(this.getScreenCTM());
            };
        </script>

        <div id="links-patterns" class="tutorial">

            <h2>Links and patterns</h2>

            <p><b>TL;DR</b>: Jump right into the <a href="#pipes-demo" target="_self">demo</a> below.</p>

            <p>This tutorial shows another way how to style JointJS links, especially if only changing the stroke color and
                width of your links is not sufficient to meet your requirements.
                What gives us more flexibility is <b>SVG gradients</b> and <b>SVG patterns</b>. SVG gradients as filling for
                strokes would be fine enough if we were using only straight links with no vertices.
                This is because the gradients are applied on the link SVG path as a whole. Therefore, applying the gradient
                on the link SVG path stroke would give different parts of the links different colors depending on how the
                link is
                broken and where it is positioned. This gives us an unpredictable result that we most likely don't want.
                Meet SVG patterns!

            <div>
                <?xml version="1.0" standalone="no"?>
                <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
                <svg width="600" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg">

                <defs>
                <pattern id="path-pattern" patternUnits="userSpaceOnUse" x="0" y="0" width="160" height="160">
                    <image id="logo"
                           xlink:href=""
                           width="160" height="160"/>
                </pattern>
                </defs>

                <path stroke="black" stroke-width="20" d="M 10 20 L 80 130 150 20" fill="none"/>
                <use transform="translate(200,0)" xlink:href="#logo"/>
                <path transform="translate(400,0)" stroke="url(#path-pattern)" stroke-width="20"
                      d="M 10 20 L 80 130 150 20" fill="none"/>
                <text x="160" y="80" font-size="40" fill="black">+</text>
                <text x="380" y="80" font-size="40" fill="black">=</text>
                </svg>
            </div>

            <p>The idea is simple. We create and render a link. We create an
                <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Canvas" target="_blank">HTML 5 canvas element</a> of the size of
                the bounding box of the link. We draw onto the canvas anything we'd like the link to look like. We generate
                a <a href="http://en.wikipedia.org/wiki/Data_URI_scheme" target="_blank">Data URI image</a> from the canvas
                and tell the link to use this image as an SVG pattern for the link stroke. And we repeat all this every time
                the link gets changed.</p>

            <h3 id="linkview">About the LinkView</h3>

            <p>A link view is responsible for rendering and updating a link, it manipulates the DOM elements and it is the
                right place to implement a link interaction or customize the link appearance.</p>

            <p>Each time we change a link attribute, source or target, we add a vertex or we move an element that is
                connected to the link - the link has to be updated.
                Normally, the <a href="/docs/jointjs/v1.0/joint.html#dia.LinkView" target="_top">joint.dia.LinkView</a> takes care of this.
                It inherits from the <a href="http://backbonejs.org/#View" target="_blank">Backbone.View</a> and extends it
                by new methods and properties. We're going to introduce some of them.
                <br>
                <br>The <code>linkView.render()</code> method creates SVG elements from the defined link markup and appends
                them to the DOM.
                It's usually called only once when link is created. Also, it calls update() internally.
                <br>The <code>linkView.update()</code> method applies all the attributes to the DOM elements, finds the
                route, positions the link tools and arrowheads and so on. It is called everytime the link is changed.
                <br>The <code>linkView.remove()</code> cleans up SVG elements from the DOM and removes event handlers.
                Called once the view is removed.
                <br>The <code>linkView.sourcePoint</code> and <code>linkView.targetPoint</code> are cached coordinates of a
                point where the link connects to an element or point.
                <br>The <code>linkView.route</code> is a cached array of points calculated from the vertices by a
                <a href="/docs/jointjs/v1.0/joint.html#dia.Link" target="_blank">router</a>.
                <br>The <code>linkView.paper</code> is a reference to the paper the view is rendered into.
            </p>

            <p>The <code>joint.dia.LinkView</code> can be extended and used, for example, in the following way:</p>

            <pre><code class="language-javascript">joint.dia.LinkView.extend({

    render: function() {

        // call parent's render
        joint.dia.LinkView.prototype.render.apply(this, arguments);

        // here we create and append the pattern into the paper SVG &lt;defs&gt; element
        // and tell the link to use it

        // it is a good convetion to return `this` to enable chaining
        return this;
    },

    remove: function() {

        // call parent's remove first
        joint.dia.LinkView.prototype.remove.apply(this, arguments);

        // here we remove the pattern from the paper SVG &lt;defs&gt; element

        return this;
    },

    update: function() {

        // call parent's update first
        joint.dia.LinkView.prototype.update.apply(this, arguments);

        // here we generate an image and set it as a pattern

        return this;
    }
});</code></pre>

            <h3 id="render">Creating a pattern</h3>

            <p>First of all we have to create an SVG pattern with an image element inside and append it to the DOM
                (specifically into the paper <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs" target="_blank">SVG
                    <code>&lt;defs&gt;</code> element</a> - this is a good place in SVG documents where referenced elements
                are defined).
                The perfect place for this is the <code>linkView.render()</code> method.
                Here we can also cache some important elements we will be using during the updates in order to minimize DOM
                traversal.</p>

            <pre><code class="language-javascript">render: function() {

    joint.dia.LinkView.prototype.render.apply(this, arguments);

    // make sure that pattern doesn't already exist
    if (!this.pattern) {

        // create the pattern and the image element
        this.pattern = V('&lt;pattern id="pattern-' + this.id + '" patternUnits="userSpaceOnUse"&gt;&lt;image/&gt;&lt;/pattern&gt;');

        // cache the image element for a quicker access
        this.patternImage = this.pattern.findOne('image');

        // append the pattern to the paper's defs
        V(this.paper.svg).defs().append(this.pattern);
    }

    // tell the '.connection' path to use the pattern
    var connection = V(this.el).findOne('.connection').attr({
        stroke: 'url(#pattern-' + this.id + ')'
    });

    // cache the stroke width
    this.strokeWidth = connection.attr('stroke-width') || 1;

    return this;
}</code></pre>

            <p>Note that we're using the <a href="/docs/jointjs/v1.0/vectorizer.html" target="_top">built-in Vectorizer library</a> for creating SVG.</p>

            <h3 id="update">Using the pattern</h3>

            <p>Once we are able to get the link's bounding box (the one without transformations), we can create an HTML 5
                canvas of the size of the bounding box of the link.
                We know the points which the link goes through (<code>sourcePoint</code>, <code>targetPoint</code> and
                <code>route</code>) so the next thing is to transform them into the link coordinate system (the coordinates
                of the link top-left corner are obtained from its bounding box).

                <br>For example if we have a bounding box <code>{ x: 100, y: 30, width: 200, height: 200 }</code> and a
                vertex with coordinates <code>{ x: 150, y: 150 }</code> the position of that vertex on the canvas is <code>{
                    x: 50, y: 120 }</code>.
                Now we have all we need to be able to draw our pattern into the canvas (more info on how to draw into the
                canvas can be found <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial"
                                       target="_blank">here</a>).</p>

            When we finish with drawing we set the pattern's coordinates and the dimensions to reflect the link bounding
            box.
            We set the <code>xlink:href</code> attribute of the image element inside the pattern to the data URI containing
            a representation of the image in the PNG format (we can obtain it from the canvas by calling <code>canvas.toDataURL('image/png')</code>).

            <pre><code class="language-javascript">update: function() {

    joint.dia.LinkView.prototype.update.apply(this, arguments);

    var strokeWidth = this.strokeWidth;

    // we get the bounding box of the linkView without the transformations
    // and expand it to all 4 sides by the stroke width
    // (making sure there is always enough room for drawing,
    // even if the bounding box was tiny.
    // Note that the bounding box doesn't include the stroke.)
    var bbox = g.rect(V(this.el).bbox(true)).moveAndExpand({
        x: - strokeWidth,
        y: - strokeWidth,
        width: 2 * strokeWidth,
        height: 2 * strokeWidth
    });

    // create an array of all the points the link goes through
    // (route doesn't contain the connection points)
    var points = [].concat(this.sourcePoint, this.route, this.targetPoint);

    // transform all the points to the link coordinate system
    points = _.map(points, function(point) {
        return g.point(point.x - bbox.x, point.y - bbox.y);
    });

    // create a canvas of the size same as the link bounding box
    var canvas = document.createElement('canvas');
    canvas.width = bbox.width;
    canvas.height = bbox.height;

    var ctx = canvas.getContext('2d');
    ctx.lineWidth = strokeWidth;

    // iterate over the points and draw the link's new look into the canvas
    for (var i = 0, pointsCount = points.length - 1; i < pointsCount; i++) {

        var from = points[i];
        var to = point[i + 1];

        // draw something into the canvas
        // e.g a line from 'from.x','from.y' to 'to.x','to.y'
    }

    // generate data URI from the canvas
    var dataUri = canvas.toDataURL('image/png');

    // set the pattern's size to the size of the link bounding box
    this.pattern.attr(bbox);

    // update the pattern image and the dimensions
    this.patternImage.attr({
        width: bbox.width,
        height: bbox.height,
        'xlink:href': dataUri
    });

    return this;
}</code></pre>

            <h3 id="remove">Removing the pattern</h3>

            <p>It's a good practice to clean up when the link gets removed from the paper. We don't want to leave
                unreferenced pattern elements in the DOM.</p>

            <pre><code class="language-javascript">remove: function() {

    joint.dia.LinkView.prototype.remove.apply(this, arguments);

    // remove the pattern from the DOM
    this.pattern.remove();
}</code></pre>

            <h3 id="workaround">Pure vertical and horizontal lines</h3>

            <p>There is one more thing we have to deal with.
                According to the SVG specification it is not possible to apply patterns on elements with no width or no
                height.</p>

            <blockquote>
                <q>Keyword objectBoundingBox should not be used when the geometry of the
                    applicable element has no width or no height, such as the case of a
                    horizontal or vertical line, even when the line has actual thickness when
                    viewed due to having a non-zero stroke width since stroke width is ignored
                    for bounding box calculations. When the geometry of the applicable element
                    has no width or height and objectBoundingBox is specified, then the given
                    effect (e.g., a gradient or a filter) will be ignored.</q>
            </blockquote>

            <p>That means, in our case, that we can't use patterns for drawing pure vertical and pure horizontal links.</p>

            <pre><code class="language-markup">&lt;!-- pure vertical path (height 0)--&gt;
&lt;path d="M 0 0 L 300 0"/&gt;

&lt;!-- pure horizontal path (width 0)--&gt;
&lt;path d="M 100 0 100 50 100 100"/&gt;</code></pre>

            <p>To overcome this issue, we can offset one of the path points by a small number.</p>

            <pre><code class="language-markup">&lt;!-- vertical path (height 0.01) --&gt;
&lt;path d="M 0 0 L 300 0.01"/&gt;

&lt;!-- horizontal path (width 0.01)--&gt;
&lt;path d="M 100 0 100 50 100.01 100"/&gt;</code></pre>

            <p>The best place where to deal with this is the link connector (connectors are responsible for generating the
                link path by constructing its <code>d</code> attribute).
                Here we take <code>joint.connectors.normal</code>, change the method name to <code>normalDimFix</code> and
                add a very small number to x and y coordinates of the last point of the resulting path.</p>

            <pre><code class="language-javascript">joint.connectors.normalDimFix = function(sourcePoint, targetPoint, vertices) {

    var dimensionFix = 1e-3;

    var d = ['M', sourcePoint.x, sourcePoint.y];

    _.each(vertices, function(vertex) { d.push(vertex.x, vertex.y); });

    d.push(targetPoint.x + dimensionFix, targetPoint.y + dimensionFix);

    return d.join(' ');
};</code></pre>

            <h3 id="pipes-demo">The pipes demo</h3>

            <p>Let's combine all this together and create a link which looks like a pipe.
                The demo below contains all that we described so far, plus it is adding some new features.
                <br>The LinkView draws into the canvas and updates the pattern asynchronously (using
                <a href="/docs/jointjs/v1.0/joint.html#util.nextFrame" target="_top">joint.util.nextFrame</a>).
                <br>It automatically creates a gradient with a directions perpendicular to the path direction for each link
                segment. This way you can style your link from the 'border' to 'border' and draw an image like the one
                below.</p>
            <img src=""
                 width="316" height="67"/>
            <br>It also separates the drawing function from the <code>update()</code> into a new linkView method <code>drawPattern()</code>.<br/>

            <div id="paper-pipes"></div>

            <p>The <a href="js/pipes.js">source code</a> to the demo.</p>

            <script type="text/javascript" src="js/pipes.js"></script>
            <pre data-src="js/pipes.js" style="height: 4880px"></pre>

        </div>

        <script src="../node_modules/prismjs/prism.js"></script>

    </body>
</html>
